package jpath

import (
	"bytes"
	"errors"
	"fmt"
	"gitee.com/tiger000/taishan_web/jpath/tokenizers"
	"gitee.com/tiger000/taishan_web/taishan"
	"gitee.com/tiger000/taishan_web/utils/ctx_parser"
	"github.com/bytedance/sonic"
	"github.com/bytedance/sonic/ast"
	"runtime"
	"strconv"
)

var ErrJpath = errors.New("jpath err")
var ErrNil = errors.New("Nil")

/**
Jpath 语法

jpath: '$' jparams
jparams: req | resp
req: 'req' (op)*
resp: 'resp' (op)*
op: arrayOp | subOp
subOp: '.' "path"|"query" | "body" | Identifier
arrayOp: arrayScopeOp | arraySubOp
arrayScopeOp:  '[]' | '[' IntegerLiteral ':' IntegerLiteral ']
arraySubOp: '[' IntegerLiteral ']
*/

// Node 节点
type Node interface {
	Run(node *ast.Node) (value *ast.Node, err error)
}

type JExpress struct {
	SourceCode string
	Jparam     JParams
}

// PanicTrace trace panic stack info.
func PanicTrace(kb int) []byte {
	s := []byte("/src/runtime/panic.go")
	e := []byte("\ngoroutine ")
	line := []byte("\n")
	stack := make([]byte, kb<<10) //4KB
	length := runtime.Stack(stack, true)
	start := bytes.Index(stack, s)
	stack = stack[start:length]
	start = bytes.Index(stack, line) + 1
	stack = stack[start:]
	end := bytes.LastIndex(stack, line)
	if end != -1 {
		stack = stack[:end]
	}
	end = bytes.Index(stack, e)
	if end != -1 {
		stack = stack[:end]
	}
	stack = bytes.TrimRight(stack, "\n")
	return stack
}
func (that *JExpress) Run(ctx *taishan.Context) (*ast.Node, error) {
	defer func() {
		if r := recover(); r != nil {
			stack := PanicTrace(1024)
			fmt.Println(r)
			fmt.Println(string(stack))
		}
	}()
	node, err := that.Jparam.RunCtx(ctx)
	if err != nil {
		return nil, errors.Join(errors.New(that.SourceCode), err)
	}
	return node, nil
}
func (that *JExpress) RunCallback(ctx *taishan.Context) (*ast.Node, func() error, error) {
	defer func() {
		if r := recover(); r != nil {
			stack := PanicTrace(1024)
			fmt.Println(r)
			fmt.Println(string(stack))
		}
	}()
	node, rewrite, err := that.Jparam.RunCtxCallback(ctx)
	if err != nil {
		return nil, nil, errors.Join(errors.New(that.SourceCode), err)
	}
	return node, rewrite, nil
}

func NewJExpress(jParams JParams) *JExpress {
	return &JExpress{Jparam: jParams}
}

type JParams interface {
	RunCtx(ctx *taishan.Context) (*ast.Node, error)
	RunCtxCallback(ctx *taishan.Context) (value *ast.Node, rewriteBack func() error, err error)
}

type ReqJparam struct {
	Sub []JParams
	Ops []Op
}

func (that *ReqJparam) RunCtx(ctx *taishan.Context) (value *ast.Node, err error) {
	var errAll error

	for _, jparams := range that.Sub {
		value, err = jparams.RunCtx(ctx)
		if err != nil {
			errAll = errors.Join(errAll, err)
			continue
		}

		if value == nil || value.Type() == V_NONE || value.Type() == V_NULL || value.Type() == V_ERROR {
			continue
		}

		for _, op := range that.Ops {
			value, err = op.Run(value)
			if err != nil {
				errAll = errors.Join(errAll, err)
				goto SUBLOOP
			}
		}
		return
	SUBLOOP:
	}

	return nil, errAll
}
func (that *ReqJparam) RunCtxCallback(ctx *taishan.Context) (value *ast.Node, rewriteBack func() error, err error) {
	var errAll error

	for _, jparams := range that.Sub {
		value, rewriteBack, err = jparams.RunCtxCallback(ctx)
		if err != nil {
			errAll = errors.Join(errAll, err)
			continue
		}

		if value == nil || value.Type() == V_NONE || value.Type() == V_NULL || value.Type() == V_ERROR {
			continue
		}

		for _, op := range that.Ops {
			value, err = op.Run(value)
			if err != nil {
				errAll = errors.Join(errAll, err)
				goto SUBLOOP
			}
		}

		return value, rewriteBack, err
	SUBLOOP:
	}

	return nil, nil, errAll
}

type RespJparam struct {
	Sub []JParams
	Ops []Op
}

func (that *RespJparam) RunCtx(ctx *taishan.Context) (value *ast.Node, err error) {
	for _, jparams := range that.Sub {
		value, err = jparams.RunCtx(ctx)
		if err != nil {

		}
		if value == nil || value.Type() == V_NONE || value.Type() == V_NULL || value.Type() == V_ERROR {
			continue
		} else {
			break
		}
	}

	if err != nil {
		return nil, err
	}

	for _, op := range that.Ops {
		value, err = op.Run(value)
		if err != nil {
			return nil, err
		}
	}

	return
}

func (that *RespJparam) RunCtxCallback(ctx *taishan.Context) (value *ast.Node, rewriteBack func() error, err error) {
	for _, jparams := range that.Sub {
		value, rewriteBack, err = jparams.RunCtxCallback(ctx)
		if err != nil {

		}
		if value == nil || value.Type() == V_NONE || value.Type() == V_NULL || value.Type() == V_ERROR {
			continue
		} else {
			break
		}
	}

	if err != nil {
		return nil, nil, err
	}

	for _, op := range that.Ops {
		value, err = op.Run(value)
		if err != nil {
			return nil, nil, err
		}
	}

	return
}

type Op interface {
	Node
}

type SubOp struct {
	Name string
}

func (that *SubOp) Run(data *ast.Node) (*ast.Node, error) {
	//判断node是否是对象
	if data.Type() == V_OBJECT { //v_object
		node := data.Get(that.Name)
		if !node.Valid() {
			return nil, errors.Join(ErrJpath, errors.New(that.Name+"不存在"))
		}
		return node, nil
	} else if data.Type() == V_ARRAY { //v_array
		//数组依然返回数组
		var temp = make([]ast.Node, 0)
		length, _ := data.Len()
		for i := 0; i < length; i++ {
			item := data.Index(i)
			if item.Type() != V_OBJECT {
				return nil, errors.Join(ErrJpath, errors.New("."+that.Name+"必须访问对象"))
			}
			astNode := item.Get(that.Name)
			if !astNode.Valid() {
				return nil, errors.Join(ErrJpath, errors.New(that.Name+"不存在"))
			}
			temp = append(temp, *astNode)
		}
		nodeNew := ast.NewArray(temp)
		return &nodeNew, nil

	} else {
		return nil, errors.Join(ErrJpath, errors.New("."+that.Name+"必须访问对象或数组"))
	}

}

type ReqSubOpPath struct {
	Name string
}

// RunCtx SubOpQuery需要taishan.Context
func (that *ReqSubOpPath) RunCtx(ctx *taishan.Context) (*ast.Node, error) {
	node := ast.NewString(ctx.Path)
	return &node, nil
}
func (that *ReqSubOpPath) RunCtxCallback(ctx *taishan.Context) (*ast.Node, func() error, error) {
	node := ast.NewString(ctx.Path)
	return &node, func() error {
		//todo
		return nil
	}, nil
}

type ReqSubOpHost struct {
	Name string
}

// RunCtx SubOpQuery需要taishan.Context
func (that *ReqSubOpHost) RunCtx(ctx *taishan.Context) (*ast.Node, error) {
	node := ast.NewString(ctx.Request.Host)
	return &node, nil
}
func (that *ReqSubOpHost) RunCtxCallback(ctx *taishan.Context) (*ast.Node, func() error, error) {
	node := ast.NewString(ctx.Request.Host)
	return &node, func() error {
		host, err := node.String()
		if err != nil {
			return errors.Join(err, errors.New("ctx.Request.Host err"))
		}
		ctx.Request.Host = host
		return nil
	}, nil
}

type ReqSubOpQuery struct {
	Name string
}

// RunCtx SubOpQuery需要taishan.Context
func (that *ReqSubOpQuery) RunCtx(ctx *taishan.Context) (*ast.Node, error) {
	node := ctx.GetValue("$req_query")
	if node == nil {
		astNode := ctx_parser.GetQueryAst([]byte(ctx.Request.URL.RawQuery))
		ctx.SetValue("$req_query", &astNode)
		return &astNode, nil
	} else {
		astNode := node.(*ast.Node)
		return astNode, nil
	}
}
func (that *ReqSubOpQuery) RunCtxCallback(ctx *taishan.Context) (*ast.Node, func() error, error) {
	node := ctx.GetValue("$req_query")
	if node == nil {
		astNode := ctx_parser.GetQueryAst([]byte(ctx.Request.URL.RawQuery))
		ctx.SetValue("$req_query", &astNode)

		return &astNode, func() error {
			//todo
			return nil
		}, nil
	} else {
		astNode := node.(*ast.Node)
		return astNode, func() error {
			//todo
			return nil
		}, nil
	}
}

type ReqSubOpBody struct {
	Name string
}

func (that *ReqSubOpBody) RunCtx(ctx *taishan.Context) (*ast.Node, error) {
	body := ctx.ReqBody()
	//判断是否是json
	if body == nil {
		return nil, errors.Join(ErrJpath, errors.New("$req.body is null"))
	}
	if (body[0] == '[' && body[len(body)-1] == ']') || (body[0] == '{' && body[len(body)-1] == '}') {
		astNode, err := sonic.Get(body)
		if err != nil {
			return nil, errors.Join(ErrJpath, errors.New("$req.body转换json失败"))
		}
		return &astNode, nil
	} else {
		astNode := ctx_parser.GetQueryAst(body)
		return &astNode, nil
	}
}
func (that *ReqSubOpBody) RunCtxCallback(ctx *taishan.Context) (*ast.Node, func() error, error) {
	body := ctx.ReqBody()
	//判断是否是json
	if body == nil {
		return nil, nil, errors.Join(ErrJpath, errors.New("$req.body is null"))
	}
	if (body[0] == '[' && body[len(body)-1] == ']') || (body[0] == '{' && body[len(body)-1] == '}') {
		astNode, err := sonic.Get(body)
		if err != nil {
			return nil, nil, errors.Join(ErrJpath, errors.New("$req.body转换json失败"))
		}
		return &astNode, func() error {
			//todo
			return nil
		}, nil
	} else {
		astNode := ctx_parser.GetQueryAst(body)
		return &astNode, func() error {
			//todo
			return nil
		}, nil
	}
}

type RespSubOpBody struct {
	Name string
}

func (that *RespSubOpBody) RunCtx(ctx *taishan.Context) (*ast.Node, error) {
	body := ctx.RespBody()
	if body == nil || len(body) == 0 {
		return nil, errors.Join(ErrJpath, errors.New("$resp.body is null"))
	}
	//判断是否是json
	if (body[0] == '[' && body[len(body)-1] == ']') || (body[0] == '{' && body[len(body)-1] == '}') {
		astNode, err := sonic.Get(body)
		if err != nil {
			return nil, errors.Join(ErrJpath, errors.New("body转换json失败"))
		}
		return &astNode, nil
	} else {
		taishan.Error(ctx).Caller().Str("body", string(body)).Msg("返回数据必须是json")
		return nil, errors.Join(ErrJpath, errors.New("返回数据必须是json"))
	}
}
func (that *RespSubOpBody) RunCtxCallback(ctx *taishan.Context) (*ast.Node, func() error, error) {
	body := ctx.RespBody()
	if body == nil || len(body) == 0 {
		return nil, nil, errors.Join(ErrJpath, errors.New("$resp.body is null"))
	}
	//判断是否是json
	if (body[0] == '[' && body[len(body)-1] == ']') || (body[0] == '{' && body[len(body)-1] == '}') {
		astNode, err := sonic.Get(body)
		if err != nil {
			return nil, nil, errors.Join(ErrJpath, errors.New("body转换json失败"))
		}
		return &astNode, func() error {
			ctx.BodyBuffer.Reset()
			bodyNew, err := astNode.Raw()
			if err != nil {
				return errors.Join(err, errors.New("RespSubOpBody ast error"))
			}
			_, err = ctx.BodyBuffer.WriteString(bodyNew)
			return err
		}, nil
	} else {
		taishan.Error(ctx).Caller().Str("body", string(body)).Msg("返回数据必须是json")
		return nil, nil, errors.Join(ErrJpath, errors.New("返回数据必须是json"))
	}
}

type ArrayOp interface {
	Op
}
type ArraySubOp struct {
	Index int //所以
}

func (that *ArraySubOp) Run(data *ast.Node) (*ast.Node, error) {
	//判断node是否是对象
	if data.Type() != V_OBJECT { //v_object
		return nil, errors.Join(ErrJpath, errors.New("["+strconv.Itoa(that.Index)+"]必须访问对象"))
	}
	node := data.Index(that.Index)
	if !node.Valid() {
		return nil, errors.Join(ErrJpath, errors.New("数组不存在:["+strconv.Itoa(that.Index)+"]"))
	}
	return node, nil
}

type ArrayScopeOp struct {
	Start int
	End   int
}

func (that *ArrayScopeOp) Run(data *ast.Node) (*ast.Node, error) {
	//判断node是否是数组
	if !(data.Type() == V_ARRAY || data.Type() == V_STRING) { //v_array
		return nil, errors.Join(ErrJpath, errors.New("[]必须访问字符串或数组"))
	}
	/*if that.Start < 0 {
		return data, nil
	}*/

	var length int
	lenData, _ := data.Len()
	if that.End > lenData || that.End == 0 {
		length = lenData
	} else {
		length = that.End
	}

	//数组依然返回数组
	if data.Type() == V_ARRAY {
		var temp = make([]ast.Node, 0)
		for i := that.Start; i < length; i++ {
			astNode := data.Index(i)
			if !astNode.Valid() {
				return nil, errors.Join(ErrJpath, errors.New("数组不存在:["+strconv.Itoa(i)+"]"))
			}
			temp = append(temp, *astNode)
		}
		nodeNew := ast.NewArray(temp)
		return &nodeNew, nil
	} else {
		val, _ := data.String()
		if that.End > len(val) || that.End == 0 {
			length = len(val)
		} else {
			length = that.End
		}
		val = val[that.Start:length]
		nodeNew := ast.NewString(val)
		return &nodeNew, nil
	}

}

var ErrEof = errors.New("EOF")

type Parser struct {
	scanner *tokenizers.Tokenizer
}

func NewParser(scanner *tokenizers.Tokenizer) *Parser {
	return &Parser{scanner: scanner}
}

func (that *Parser) Parse() (*JExpress, error) {
	return that.parseJExpress()
}

/*
*
  - 解析Prog
  - 语法规则：
  - jpath: '$' jparams
*/
func (that *Parser) parseJExpress() (*JExpress, error) {
	token := that.scanner.Peek()
	if token.Kind != tokenizers.Start {
		return nil, errors.Join(ErrJpath, errors.New("jpath 必须以$开始，而不是"+token.Text+":"+string(token.Kind)))
	}
	that.scanner.Next()

	jparams, err := that.parseJParams()
	if err != nil {
		return nil, err
	}

	return NewJExpress(jparams), nil
}

/*
*
语法：

	params: req | resp
*/
func (that *Parser) parseJParams() (JParams, error) {
	t := that.scanner.Peek()
	if t.Kind != tokenizers.EOF {
		if t.Kind == tokenizers.Identifier {
			if t.Text == "req" {
				that.scanner.Next()
				sub, err := that.parseJParamSub("req")
				if err != nil {
					return nil, err
				}
				ops, err := that.parseOp()
				if err != nil {
					return nil, err
				}
				return &ReqJparam{sub, ops}, nil

			} else if t.Text == "resp" {
				that.scanner.Next()
				sub, err := that.parseJParamSub("resp")
				if err != nil {
					return nil, err
				}
				ops, err := that.parseOp()
				if err != nil {
					return nil, err
				}
				return &RespJparam{sub, ops}, nil
			}
		}
		return nil, errors.Join(ErrJpath, errors.New("req或resp不存在"))
	} else {
		return nil, ErrEof
	}

}

/*
语法：
req.body req.query resp.body resp.query req.query|body req.path
*/
func (that *Parser) parseJParamSub(preOp string) ([]JParams, error) {
	ops := make([]JParams, 0)
	t := that.scanner.Peek()
	if t.Kind == tokenizers.Separator && t.Text == "." {
		that.scanner.Next()
		subOp, err := that.parseSubOp()
		if err != nil {
			return nil, err
		}
		jparam, err := reqRespFormat(preOp, subOp)
		if err != nil {
			return nil, err
		}
		ops = append(ops, jparam)
		t = that.scanner.Peek()
		for t.Kind != tokenizers.EOF {
			if t.Kind == tokenizers.Separator && t.Text == "|" {
				that.scanner.Next()
				subOp, err = that.parseSubOp()
				if err != nil {
					return nil, err
				}
				jparam, err = reqRespFormat(preOp, subOp)
				if err != nil {
					return nil, err
				}
				ops = append(ops, jparam)
				t = that.scanner.Peek()
			} else {
				break
			}
		}
	} else {
		return nil, errors.Join(ErrJpath, errors.New(preOp+"需要.操作符，实际是"+t.Text))
	}

	return ops, nil
}

func reqRespFormat(preOp string, op *SubOp) (JParams, error) {
	if preOp == "req" {
		if op.Name == "query" {
			return &ReqSubOpQuery{Name: "query"}, nil
		} else if op.Name == "body" {
			return &ReqSubOpBody{Name: "body"}, nil
		} else if op.Name == "path" {
			return &ReqSubOpPath{Name: "path"}, nil
		} else if op.Name == "host" {
			return &ReqSubOpHost{Name: "host"}, nil
		} else {
			return nil, errors.Join(ErrJpath, errors.New("req只能访问host,path,query和body"))
		}
	} else if preOp == "resp" {
		if op.Name == "body" {
			return &RespSubOpBody{Name: "body"}, nil
		} else {
			return nil, errors.Join(ErrJpath, errors.New("resp只能访问body"))
		}
	}
	return nil, errors.Join(ErrJpath, errors.New(preOp+"不支持操作"+op.Name))
}

/*
*
语法：

	op: arrayOp | subOp
*/

func (that *Parser) parseOp() ([]Op, error) {
	ops := make([]Op, 0)
	t := that.scanner.Peek()
	for t.Kind != tokenizers.EOF {
		if t.Kind == tokenizers.Separator {
			if t.Text == "." {
				that.scanner.Next()
				subOp, err := that.parseSubOp()
				if err != nil {
					return nil, err
				}
				ops = append(ops, subOp)
				t = that.scanner.Peek()
				continue
			} else if t.Text == "[" {
				that.scanner.Next()
				arrayOp, err := that.parseArrayOp()
				if err != nil {
					return nil, err
				}
				ops = append(ops, arrayOp)
				t = that.scanner.Peek()
				continue
			}
		} else {
			return nil, errors.New("需要.或者[操作符，实际是" + t.Text)
		}
	}

	/*if len(ops) > 0 {
		if subOp, ok := ops[0].(*SubOp); ok {
			if preOp == "req" {
				if subOp.Name == "query" {
					ops[0] = &ReqSubOpQuery{SubOp{Name: "query"}}
				} else if subOp.Name == "body" {
					ops[0] = &ReqSubOpBody{SubOp{Name: "body"}}
				} else {
					return nil, errors.New("req只能访问query和body")
				}
			} else if preOp == "resp" {
				if subOp.Name == "body" {
					ops[0] = &RespSubOpBody{SubOp{Name: "body"}}
				} else {
					return nil, errors.New("resp只能访问body")
				}
				//return nil, errors.New("resp只能操作body")
			}
		} else {
			return nil, errors.New("req/resp只能访问query/body")
		}

	} else {
		return nil, errors.New("req/resp需要后续操作")
	}*/

	return ops, nil
}

/*
*
subOp: '.' Identifier
*/
func (that *Parser) parseSubOp() (*SubOp, error) {
	t := that.scanner.Peek()
	if t.Kind == tokenizers.EOF {
		return nil, ErrEof
	}
	if t.Kind == tokenizers.Identifier {
		that.scanner.Next()
		return &SubOp{Name: t.Text}, nil
	}
	return nil, errors.Join(ErrJpath, errors.New(string("需要标识符Identifier，实际是"+t.Kind)))
}

/*
*
arrayOp: arraysOp | arraySubOp
*/
func (that *Parser) parseArrayOp() (ArrayOp, error) {
	t := that.scanner.Peek()
	if t.Kind == tokenizers.EOF {
		return nil, ErrEof
	}
	if t.Kind == tokenizers.Separator {
		if t.Text == "]" {
			that.scanner.Next()
			return &ArrayScopeOp{
				Start: 0,
				End:   0,
			}, nil
		} else if t.Text == ":" {
			arrayScopeOp, err := that.parseArrayScopeOp()
			if err != nil {
				return nil, err
			}
			return arrayScopeOp, nil
		}
		return nil, errors.New("需要操作符:或者]，实际是" + t.Text)
	} else if t.Kind == tokenizers.Identifier {
		t1 := that.scanner.Peek2()
		if t1.Kind == tokenizers.Separator {
			if t1.Text == ":" {
				arrayScopeOp, err := that.parseArrayScopeOp()
				if err != nil {
					return nil, err
				}
				return arrayScopeOp, nil
			} else if t1.Text == "]" {
				arraySubOp, err := that.parseArraySubOp()
				if err != nil {
					return nil, err
				}
				return arraySubOp, nil
			}
		} else if t1.Kind == tokenizers.EOF {
			return nil, ErrEof
		}
		return nil, errors.New("需要操作符:或] 实际是" + t.Text)
	}
	return nil, errors.New(string("需要标识符Identifier，实际是" + t.Kind))
}

/*
*
arrayScopeOp:  '[]' | '[' IntegerLiteral ':' IntegerLiteral ']' | '[' IntegerLiteral ':' ']'
*/
func (that *Parser) parseArrayScopeOp() (*ArrayScopeOp, error) {
	t := that.scanner.Peek()
	var start int64 = 0
	if t.Text == ":" {
		start = 0
	} else {
		for _, v := range t.Text {
			if v < '0' || v > '9' {
				return nil, errors.New("需要数字 实际是" + t.Text)
			}
		}
		start, _ = strconv.ParseInt(t.Text, 10, 32)
		if start < 0 {
			start = 0
		}
		that.scanner.Next()
	}

	that.scanner.Next()

	t = that.scanner.Peek()
	if t.Kind == tokenizers.EOF {
		return nil, ErrEof
	}
	var end int64 = 0
	if t.Text == "]" {
		end = 0
	} else {
		for _, v := range t.Text {
			if v < '0' || v > '9' {
				return nil, errors.New("需要数字 实际是" + t.Text)
			}
		}
		end, _ = strconv.ParseInt(t.Text, 10, 32)
		if end < 0 {
			end = 0
		}
		that.scanner.Next()
		t = that.scanner.Peek()
	}

	if !(t.Kind == tokenizers.Separator && t.Text == "]") {
		return nil, errors.New("需要操作符] 实际是" + t.Text)
	}
	that.scanner.Next()

	/*if start < 0 || end < 0 || start >= end {
		return nil, errors.New("[" + strconv.Itoa(int(start)) + ":" + strconv.Itoa(int(end)) + "]格式错误")
	}*/

	return &ArrayScopeOp{Start: int(start), End: int(end)}, nil

}

/*
*
arraySubOp: '[' IntegerLiteral ']
*/
func (that *Parser) parseArraySubOp() (*ArraySubOp, error) {
	t := that.scanner.Peek()
	for _, v := range t.Text {
		if v < '0' || v > '9' {
			return nil, errors.New("需要数字 实际是" + t.Text)
		}
	}
	num, _ := strconv.ParseInt(t.Text, 10, 32)
	that.scanner.Next()
	that.scanner.Next()
	return &ArraySubOp{Index: int(num)}, nil
}
